//==============================================================================
//
//           DInt - the integer number class in the ofc-library
//
//               Copyright (C) 2003  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2008-08-02 05:58:14 $ $Revision: 1.12 $
//
//==============================================================================

#include "ofc/DInt.h"

#include <limits.h>
#include <stdlib.h>



#if _INTERFACE_

#include "ofc/config.h"

#include "ofc/DComparable.h"
#include "ofc/DTextable.h"
#include "ofc/DDatable.h"
#include "ofc/DParsable.h"

#include "ofc/DText.h"
#include "ofc/DData.h"

//
// The Int class implements a number of methods for storing and manipulating int numbers.
//
// @example
// #include <stdio.h>
// #include "ofc/DInt.h"
// 
// int main(int argc, char *agv[])
// {
//   DInt  *i1 = [DInt alloc];
//   DInt  *i2 = [DInt new  ];
//   DText *str;
// 
//   [i1 init :-70];                      // Init with a number
// 
//   printf("Int1 has value:%d.\n", [i1 get]); // Get value from object
// 
//   [i2 set :140];                       // Set with a number
// 
//   str = [i2 toText];
//   printf("Int2 has value:%s as string.\n", [str cstring]); // Convert value to string
//   [str free];
// 
//   if ([i1 compare :i2] == 0)           // Compare integers
//     printf("Int1 and int2 are equal.\n");
//   else if ([i1 compare :i2] < 0)
//     printf("Int1 is smaller than int2.\n");
//   else
//     printf("Int1 is greater than int2.\n");
// 
//                                        // Conversion big- and little-endian
//   printf("Int1 as little-endian (%d) and as big-endian (%d).\n", [i1 toLittleEndian], [i2 toBigEndian]);
// 
//   [i1 free];                           // Cleanup
//   [i2 free];
// 
//   return 0;
// }
//

@interface DInt : DObject <DComparable,DTextable,DDatable,DParsable>
{
@private
  int          _int;
}

#endif



@implementation DInt


//// Constructors

//
// Initialise to number zero
//
// @return the object
//

- (DInt *) init
{
  [super init];

  _int = 0;
  
  return self;
}

//
// Initialise to a number
//
// @param number   the number
//
// @return the object
//

- (DInt *) init :(int) number
{
  [self init];

  _int = number;

  return self;
}


//// Member methods

//
// Get the integer number
//
// @return the number
//

- (int) get
{
  return _int;
}

//
// Set the integer number
//
// @param number  the integer
//
// @return the object
//

- (DInt *) set :(int) number
{
  _int = number;

  return self;
}


//// Comparable protocol

//
// Compare two integer objects
//
// @param other    the object to compare with
//
// @return the result of the comparison (-1,0,1)
//

- (int) compare :(DInt *) other
{
  if (self != other)
  {
    int i = [other get];
    
    if (_int == i)
    {
      return 0;
    }
    else if (_int > i)
    {
      return 1;
    }
    else
    {
      return -1;
    }
  }
  else
  {
    return 0;
  }
}
 

//// Parsable protocol

//
// Parse a string for an int number
//
// @param cstr     the string to be parsed (moved to the first no-parsable char)
//
// @return the result (0, ERANGE, ENODATA)
//

- (int) fromString :(char **) cstr
{
  int   result = 0;
  int   number = 0;
  char *src    = *cstr;

  number = strtol(*cstr, cstr, 0);

  if (src == *cstr)
  {
    result = ENODATA;
  }
  else if ((number <= INT_MIN) || (number >= INT_MAX))
  {
    result = ERANGE;
  }
  else
  {
    _int = number;
  }

  return result;
}


//// Textable protocol

//
// Return a text string 
//
// @return a (new) text string with the integer number
//

- (DText *) toText
{
  return [[[DText alloc] init] format :"%d",_int];
}
    

//// Datable protocol

//
// Return a data string
//
// @return a (new) data string
//

- (DData *) toData
{
  return [[DData alloc] init :(unsigned char *)&_int :sizeof(_int)];
}


//// Endian methods

//
// Return the BigEndian (network order) order for the object
//
// @return the big endian converted int
//

- (int) toBigEndian
{
  int number = _int;
  
#ifndef WORDS_BIGENDIAN
  if (sizeof(int) == 2)
  {
    number = ((number >> 8) & 0x00ff) | ((number << 8) & 0xff00);
  }
  else if (sizeof(int) == 4)
  {
    number = ((number >> 24) & 0x000000ff) |
             ((number >> 8)  & 0x0000ff00) | 
             ((number << 8)  & 0x00ff0000) |
             ((number << 24) & 0xff000000);
  }
#endif
  
  return number;
}

//
// Return the LittleEndian order for the object
//
// @return the little endian converted int
//

- (int) toLittleEndian
{
  int number = _int;

#ifdef WORDS_BIGENDIAN
  if (sizeof(int) == 2)
  {
    number = ((number >> 8) & 0x00ff) | ((number << 8) & 0xff00);
  }
  else if (sizeof(int) == 4)
  {
    number = ((number >> 24) & 0x000000ff) |
             ((number >> 8)  & 0x0000ff00) | 
             ((number << 8)  & 0x00ff0000) |
             ((number << 24) & 0xff000000);
  }
#endif

  return number;
}

@end

/*==========================================================================*/
         
